/******************************************************************************
*  author: enquanyan
*  version: 1.0
*  description:
*  			http_conn header file;
*  			initialize listening socket and thread pool;
*  			perform epoll_wait;
*  date: 2014-07-21
*  other: 无
******************************************************************************/

#ifndef HTTPCONNECTION_H
#define HTTPCONNECTION_H

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <stdarg.h>
#include <errno.h>
#include <dirent.h>
#include <sys/sendfile.h>

#include <iostream>
#include <string>

#include "locker.h"
#include "def.h"
#include "threadpool.h"
#include "util.h"

#include "abstract_conn.h"
#include "forward_conn.h"


//set file descriptor to non-block
extern int setnonblocking(int fd);

//add fd to epoll
extern int addfd(int epollfd, int fd, bool one_shot);

int addfd_EPOLLOUT(int epollfd, abstract_conn *abstract_conn_ptr, int fd, bool one_shot);

//remove fd from epoll
extern int removefd(int epollfd, int fd, bool is_in_epoll = true);

//modify fd
extern int modfd(int epollfd, int fd, int ev, bool is_in_epoll = true);

class http_conn : public abstract_conn
{
    public:
        
        //typedef bool (http_conn::*read_handle_t)();

        //typedef bool (http_conn::*write_handle_t)();

    public:
    
        http_conn();
        
        virtual ~http_conn();

    public:
        virtual void init(int sockfd, const sockaddr_in& addr);
        virtual void close_conn(bool real_close = true);
        virtual void process(void);

    private:
        void init();

        READ_STATUS read_request(void);
        READ_STATUS read_request_line_and_headers(void);
        READ_STATUS read_request_content(void);

        //parse request functions
        HTTP_CODE parse_request(void);
        HTTP_CODE parse_request_line(char* text);
        HTTP_CODE parse_request_line(void);
        HTTP_CODE parse_headers(char* text);
        HTTP_CODE parse_headers(void);
        HTTP_CODE parse_post_content_headers(char* text);
        HTTP_CODE parse_post_content_headers(void);
        HTTP_CODE parse_post_content(void);
        HTTP_CODE parse_content(char* text);
        LINE_STATUS parse_post_content_header_line(void);
        LINE_STATUS get_content_line(void);
        LINE_STATUS parse_line(void);
        char* get_line(void) {
            return m_read_buf + m_start_line;
        }
        char* get_content_hearder_line(void) {
            return m_content_buf;
        }

        HTTP_CODE read_handle_func(void);

        //handle request
        HTTP_CODE judge_request_type();
        void unmap();
        bool add_response(const char* format, ...);
        bool add_content(const char* content);
        bool add_status_line(int status, const char* title);
        bool add_headers(int content_length);
        bool add_content_length(int content_length);
        bool add_linger(void);
        bool add_blank_line(void);

        bool write_response(void);
        bool generate_response(HTTP_CODE ret);
        HTTP_CODE write_handle_func(void);

        char* list_dir(char *path);

    public:
        static int m_epollfd;
        static int m_user_count;
        
        //read_handle_t read_handle;
        //write_handle_t write_handle;

        bool is_have_end;

    private:
        
        sockaddr_in m_address;

        int upload_file_id;
        int download_file_id;
        
        int write_count;
        long int write_file_count;
        unsigned long long download_file_size;

        char m_read_buf[READ_BUFFER_SIZE];
        int m_read_idx;
        int m_checked_idx;

        char m_content_buf[READ_BUFFER_SIZE];
        int m_content_idx;
        int m_content_checked_idx;
        int end_line;
        bool is_file_content;

        int m_start_line;
        char m_write_buf[WRITE_BUFFER_SIZE];
        int m_write_idx;

        CHECK_STATE m_check_state;
        METHOD m_method;

        char m_real_file[FILENAME_LEN];
        char list_dir_content[LISTDIRCONTENT_LEN];
        
        char* m_url;
        char* m_version;
        char* m_host;
        char* m_content_type;
        char* boundary;
        char* m_referer;
        unsigned long long m_content_length;
        bool m_linger;

        char *m_file_address;
        struct stat m_file_stat;
        
        //parse post content
        int boundary_length;
        int end_boundary_length;
        
        bool is_in_epoll;
        
        std::map<char*, char*, classcomp> para_map;
};

#endif
